package com.bestcem.xm.txtanls.dao.impl.mysql;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.ObjectId;
import cn.hutool.core.lang.Validator;
import com.bestcem.xm.common.core.constant.Constants;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.common.core.uitls.StringUtil;
import com.bestcem.xm.txtanls.dao.AnalysisProjectDao;
import com.bestcem.xm.txtanls.dao.dto.PageDTO;
import com.bestcem.xm.txtanls.dao.mapper.ProjectFieldMapper;
import com.bestcem.xm.txtanls.dao.mapper.TxtanlsProjectMapper;
import com.bestcem.xm.txtanls.entity.mysql.ProjectEntity;
import com.bestcem.xm.txtanls.entity.mysql.ProjectFieldEntity;
import com.bestcem.xm.txtanls.entity.pojo.ProjectDO;
import com.bestcem.xm.txtanls.entity.pojo.ProjectFieldDO;
import com.bestcem.xm.txtanls.enums.AnalysisStatusEnum;
import com.bestcem.xm.txtanls.enums.ProjectFieldTypeEnum;
import com.bestcem.xm.txtanls.enums.TrainStatusEnum;
import com.bestcem.xm.txtanls.grpc.service.param.PageParam;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author liheng
 * @version v1.0
 * @date 2021/6/28 14:08
 */
@Repository
public class AnalysisProjectDaoImpl implements AnalysisProjectDao {

    @Resource
    private TxtanlsProjectMapper txtanlsProjectMapper;

    @Resource
    private ProjectFieldMapper projectFieldMapper;

    @Override
    public ProjectDO findById(String projectId) {
        ProjectEntity projectEntity = txtanlsProjectMapper.selectByProjectId(projectId);
        return toProjectDO(projectEntity);
    }

    /**
     * 根据状态获取第一个满足的文本分析项目
     *
     * @param status 项目状态
     * @return 文本分析项目
     */
    @Override
    public ProjectDO findOneByStatus(int status) {
        List<ProjectEntity> projectEntities = txtanlsProjectMapper.findAllByStatus(status);
        if (CollectionUtils.isEmpty(projectEntities)) {
            return null;
        }
        return toProjectDO(projectEntities.get(0));
    }

    /**
     * 根据状态获取所有满足的文本分析项目
     *
     * @param status 项目状态
     * @return 文本分析项目列表
     */
    @Override
    public List<ProjectDO> findAllByStatus(int status) {
        List<ProjectEntity> projectEntities = txtanlsProjectMapper.findAllByStatus(status);
        return toProjectDOList(projectEntities);
    }

    /**
     * 根据项目名称和创建用户查询文本分析项目
     *
     * @param projectName 项目名字
     * @param userId      用户id
     * @return 文本分析项目
     */
    @Override
    public ProjectDO findByNameAndCreator(String projectName, String userId) {
        ProjectEntity projectEntity = txtanlsProjectMapper.findByNameAndCreator(projectName, userId);
        return toProjectDO(projectEntity);
    }

    /**
     * 获取用户创建的所有文本分析项目
     * 分页
     *
     * @param userId    用户id
     * @param pageParam 分页参数
     * @return 文本分析项目列表
     */
    @Override
    public PageDTO<ProjectDO> findUserAllProject(String userId, PageParam pageParam, String name, Integer status) {
        List<Integer> statuses = Arrays.asList(AnalysisStatusEnum.INACTIVE.getIndex(),
                AnalysisStatusEnum.ACTIVE.getIndex(), AnalysisStatusEnum.FINISHED.getIndex(),
                AnalysisStatusEnum.FAILED.getIndex(), AnalysisStatusEnum.CREATED.getIndex());

        int total = txtanlsProjectMapper.count(userId, "", true, statuses, name, status);
        if (total == 0) {
            return new PageDTO<>(new ArrayList<>(), 0L);
        }
        int offset = pageParam.getSize() * (pageParam.getPage() > 0 ? pageParam.getPage() - 1 : 0);
        List<ProjectEntity> projectEntities = txtanlsProjectMapper.pageList(userId, "", true, statuses,
                "create_time desc", offset, pageParam.getSize(), name, status);
        List<ProjectDO> projectDOList = toProjectDOList(projectEntities);
        return new PageDTO<>(projectDOList, (long) total);
    }

    /**
     * 获取属于对应组织的所有文本分析项目
     * 分页
     *
     * @param orgId     组织id
     * @param pageParam 分页参数
     * @return 文本分析项目结果页
     */
    @Override
    public PageDTO<ProjectDO> findOrganizationAllProject(String orgId, PageParam pageParam, String name, Integer status) {
        List<Integer> statuses = Arrays.asList(AnalysisStatusEnum.INACTIVE.getIndex(),
                AnalysisStatusEnum.ACTIVE.getIndex(), AnalysisStatusEnum.FINISHED.getIndex(),
                AnalysisStatusEnum.FAILED.getIndex(), AnalysisStatusEnum.CREATED.getIndex());

        int total = txtanlsProjectMapper.count("", orgId, true, statuses, name, status);
        if (total == 0) {
            return new PageDTO<>(new ArrayList<>(), 0L);
        }
        int offset = pageParam.getSize() * (pageParam.getPage() > 0 ? pageParam.getPage() - 1 : 0);
        List<ProjectEntity> projectEntities = txtanlsProjectMapper.pageList("", orgId, true, statuses,
                "create_time desc", offset, pageParam.getSize(), name, status);
        List<ProjectDO> projectDOList = toProjectDOList(projectEntities);
        return new PageDTO<>(projectDOList, (long) total);
    }

    /**
     * 获取所有使用了对应文本字段的文本分析项目
     *
     * @param textFieldId 文本字段id
     * @return 文本分析项目
     */
    @Override
    public List<ProjectDO> findAllProjectByFieldId(String textFieldId) {
        List<ProjectDO> projectDOList = new ArrayList<>();
        // 根据fieldId获取projectId
        List<String> projectIdList = projectFieldMapper.listProjectIdsByFieldId(textFieldId);
        for (String projectId : projectIdList) {
            // 根据projectId获取所有文本字段类型的字段
            List<ProjectFieldEntity> projectFieldEntityList = projectFieldMapper.listProjectField(projectId, Constants.ONE);
            List<ProjectFieldDO> projectFieldDOList = projectFieldEntityList.stream().map(this::toProjectFieldDO).collect(Collectors.toList());
            // 根据projectId获取project
            ProjectDO projectDO = findById(projectId);
            if (Validator.isNotNull(projectDO)) {
                // 封装结果 放入list
                projectDOList.add(toProjectDO(projectDO, projectFieldDOList));
            }
        }
        return projectDOList;
    }

    /**
     * 获取问卷分析项目
     *
     * @param surveyId 问卷id
     * @return 问卷分析项目
     */
    @Override
    public ProjectDO findSurveyAnalysisProject(String surveyId) {
        ProjectEntity projectEntity = txtanlsProjectMapper.selectBySurveyId(surveyId);
        return toProjectDO(projectEntity);
    }

    /**
     * 插入文本分析项目
     *
     * @param projectDO 文本分析项目初始属性
     * @return 文本分析项目初始属性
     */
    @Override
    public ProjectDO insertProject(ProjectDO projectDO) {
        String projectId = ObjectId.next();
        // 先保存字段信息
        // 设置时间字段
        if (Validator.isNotEmpty(projectDO.getTimeFieldId()) && Validator.isNotEmpty(projectDO.getTimeFieldName())) {
            ProjectFieldEntity timeFieldEntity = new ProjectFieldEntity();
            timeFieldEntity.setProjectFieldId(StringUtil.getId());
            timeFieldEntity.setProjectId(projectId);
            timeFieldEntity.setFieldId(projectDO.getTimeFieldId());
            timeFieldEntity.setFieldName(projectDO.getTimeFieldName());
            timeFieldEntity.setType(ProjectFieldTypeEnum.TIME.getIndex());
            timeFieldEntity.setCreatorId(projectDO.getUserId());
            timeFieldEntity.setOperatorId(projectDO.getUserId());
            timeFieldEntity.setCreateTime(DateUtil.getCommonDate());
            timeFieldEntity.setUpdateTime(DateUtil.getCommonDate());
            projectFieldMapper.insert(timeFieldEntity);
        }
        // 设置文本字段
        if (CollUtil.isNotEmpty(projectDO.getTextFieldList())) {
            for (ProjectFieldDO projectFieldDO : projectDO.getTextFieldList()) {
                ProjectFieldEntity textFieldEntity = new ProjectFieldEntity();
                textFieldEntity.setProjectFieldId(StringUtil.getId());
                textFieldEntity.setFieldId(projectFieldDO.getId());
                textFieldEntity.setProjectId(projectId);
                textFieldEntity.setFieldName(projectFieldDO.getValue());
                textFieldEntity.setType(ProjectFieldTypeEnum.TEXT.getIndex());
                textFieldEntity.setCreatorId(projectDO.getUserId());
                textFieldEntity.setOperatorId(projectDO.getUserId());
                textFieldEntity.setUpdateTime(DateUtil.getCommonDate());
                textFieldEntity.setCreateTime(DateUtil.getCommonDate());
                projectFieldMapper.insert(textFieldEntity);
            }
        }
        ProjectEntity projectEntity = toProjectEntity(projectDO);
        projectEntity.setProjectId(projectId);
        if (Objects.isNull(projectDO.getCreatedDate())) {
            projectEntity.setCreateTime(DateUtil.getCommonDate());
        }
        if (Objects.isNull(projectDO.getUpdatedDate())) {
            projectEntity.setUpdateTime(DateUtil.getCommonDate());
        }
        txtanlsProjectMapper.insert(projectEntity);
        projectDO.setId(projectId);
        return projectDO;
    }

    /**
     * 更新文本分析项目
     * 传参需满足配置的 Validation 规则, 否则触发快速失败
     *
     * @param projectDO 文本分析项目
     * @return 更新的条数
     */
    @Override
    public int updateProject(ProjectDO projectDO) {
        ProjectEntity projectEntity = toProjectEntity(projectDO);
        projectFieldMapper.deleteByProjectIdAndType(projectDO.getId(), ProjectFieldTypeEnum.TEXT.getIndex());
        projectFieldMapper.deleteByProjectIdAndType(projectDO.getId(), ProjectFieldTypeEnum.TIME.getIndex());
        if (Validator.isNotEmpty(projectDO.getTimeFieldId()) && Validator.isNotEmpty(projectDO.getTimeFieldName())) {
            ProjectFieldEntity timeFieldEntity = new ProjectFieldEntity();
            timeFieldEntity.setProjectFieldId(StringUtil.getId());
            timeFieldEntity.setFieldId(projectDO.getTimeFieldId());
            timeFieldEntity.setFieldName(projectDO.getTimeFieldName());
            timeFieldEntity.setProjectId(projectDO.getId());
            timeFieldEntity.setType(ProjectFieldTypeEnum.TIME.getIndex());
            timeFieldEntity.setCreatorId(projectDO.getUserId());
            timeFieldEntity.setOperatorId(projectDO.getUserId());
            timeFieldEntity.setUpdateTime(DateUtil.getCommonDate());
            timeFieldEntity.setCreateTime(DateUtil.getCommonDate());
            projectFieldMapper.insert(timeFieldEntity);
        }
        // 设置文本字段
        if (CollUtil.isNotEmpty(projectDO.getTextFieldList())) {
            for (ProjectFieldDO projectFieldDO : projectDO.getTextFieldList()) {
                ProjectFieldEntity textFieldEntity = new ProjectFieldEntity();
                textFieldEntity.setProjectFieldId(StringUtil.getId());
                textFieldEntity.setFieldId(projectFieldDO.getId());
                textFieldEntity.setFieldName(projectFieldDO.getValue());
                textFieldEntity.setProjectId(projectDO.getId());
                textFieldEntity.setType(ProjectFieldTypeEnum.TEXT.getIndex());
                textFieldEntity.setCreatorId(projectDO.getUserId());
                textFieldEntity.setOperatorId(projectDO.getUserId());
                textFieldEntity.setUpdateTime(DateUtil.getCommonDate());
                textFieldEntity.setCreateTime(DateUtil.getCommonDate());
                projectFieldMapper.insert(textFieldEntity);
            }
        }
        projectEntity.setOperatorId(projectDO.getUserId());
        projectEntity.setUpdateTime(DateUtil.getCommonDate());
        return txtanlsProjectMapper.updateByProjectId(projectEntity);
    }

    /**
     * 更新文本分析项目状态
     *
     * @param projectId 项目id
     * @param status    目标状态
     * @return 更新的条数
     */
    @Override
    public int updateAnalysisProjectStatus(String projectId, int status) {
        ProjectEntity projectEntity = new ProjectEntity();
        projectEntity.setProjectId(projectId);
        projectEntity.setStatus(status);
        projectEntity.setUpdateTime(DateUtil.getCommonDate());
        return txtanlsProjectMapper.updateByProjectId(projectEntity);
    }

    /**
     * 更新训练进度和训练状态到项目表
     *
     * @param projectId     项目id
     * @param status        目标状态
     * @param trainProgress 训练进度，剩余的条数
     * @return 更新的条数
     */
    @Override
    public int updateAnalysisProjectProgress(String projectId, TrainStatusEnum status, long trainProgress) {
        ProjectEntity projectEntity = new ProjectEntity();
        projectEntity.setProjectId(projectId);
        projectEntity.setTrainStatus(Integer.valueOf(status.getName()));
        projectEntity.setTrainProgress((int) trainProgress);
        projectEntity.setUpdateTime(DateUtil.getCommonDate());
        return txtanlsProjectMapper.updateByProjectId(projectEntity);
    }

    /**
     * 更新所有使用对应数据源的文本分析项目的数据表名称
     *
     * @param tableId   数据表id
     * @param tableName 数据表名称
     * @return 更新的数量
     */
    @Override
    public int updateTableNameByTableId(String tableId, String tableName) {
        ProjectEntity projectEntity = new ProjectEntity();
        projectEntity.setTableId(tableId);
        projectEntity.setTableName(tableName);
        projectEntity.setUpdateTime(DateUtil.getCommonDate());
        return txtanlsProjectMapper.updateByTableId(projectEntity);
    }

    @Override
    public int updateTimeFieldByTimeId(String timeFieldId, String timeFieldName) {
        return projectFieldMapper.updateFieldNameByFieldId(timeFieldId, timeFieldName);
    }

    /**
     * 删除文本分析项目
     *
     * @param projectId 项目id
     * @return 删除的条数
     */
    @Override
    public int deleteProject(String projectId) {
        return txtanlsProjectMapper.deleteByProjectId(projectId);
    }

    @Override
    public List<String> listTextFiledId(String projectId, String fieldId) {
        // 类型为1 文本字段类型
        List<String> fieldIds = new ArrayList<>(10);
        if (StringUtils.isBlank(fieldId)) {
            fieldIds = projectFieldMapper.listFiledIdsByProjectIdAndType(projectId, ProjectFieldTypeEnum.TEXT.getIndex());
        } else {
            fieldIds.add(fieldId);
        }
        return fieldIds;
    }

    @Override
    public List<ProjectDO> findAllProjectByOrgId(String orgId, boolean surveyIdNullFlag) {
        List<Integer> statuses = Arrays.asList(AnalysisStatusEnum.INACTIVE.getIndex(),
                AnalysisStatusEnum.ACTIVE.getIndex(), AnalysisStatusEnum.FINISHED.getIndex(),
                AnalysisStatusEnum.FAILED.getIndex(), AnalysisStatusEnum.CREATED.getIndex());
        List<ProjectEntity> allProject = txtanlsProjectMapper.findAllProjectByOrgId(orgId, statuses, surveyIdNullFlag);
        return toProjectDOList(allProject);

    }

    @Override
    public void updateProjectFieldOffset(String projectId, String fieldId, int offset) {
        projectFieldMapper.updateProjectFieldOffset(projectId, fieldId, offset);
    }

    @Override
    public Long updateSampleModelId(String defaultModelId) {
        return txtanlsProjectMapper.updateSampleModelId(defaultModelId);

    }

    @Override
    public List<String> listGroupOrgId() {
        return txtanlsProjectMapper.listOrgId();
    }

    @Override
    public Long updateSetModelId(String orgId, String trainModelId) {

        return txtanlsProjectMapper.updateSetModelId(orgId, trainModelId);

    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int updateProjectFieldList(String projectId, List<ProjectFieldDO> textFields) {
        // 类型为1 文本字段类型
        // 根据projectId删除全部记录
        projectFieldMapper.deleteByProjectIdAndType(projectId, ProjectFieldTypeEnum.TEXT.getIndex());
        // 批量插入
        List<ProjectFieldEntity> projectFieldEntityList = textFields.stream().map(textField -> {
            ProjectFieldEntity entity = new ProjectFieldEntity();
            entity.setProjectFieldId(ObjectId.next());
            entity.setProjectId(projectId);
            entity.setFieldId(textField.getId());
            entity.setFieldName(textField.getValue());
            entity.setType(ProjectFieldTypeEnum.TEXT.getIndex());
            entity.setCreateTime(DateUtil.getCommonDate());
            entity.setUpdateTime(DateUtil.getCommonDate());
            return entity;
        }).collect(Collectors.toList());
        return projectFieldMapper.insertFields(projectFieldEntityList);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int updateProjectTimeField(String projectId, String timeFieldId, String timeFieldName) {
        // 类型为0 时间字段类型 目前为单选 一个projectId对应一条记录
        // 根据projectId删除记录
        projectFieldMapper.deleteByProjectIdAndType(projectId, ProjectFieldTypeEnum.TIME.getIndex());
        // 插入记录
        ProjectFieldEntity entity = new ProjectFieldEntity();
        entity.setProjectFieldId(ObjectId.next());
        entity.setProjectId(projectId);
        entity.setFieldId(timeFieldId);
        entity.setFieldName(timeFieldName);
        entity.setType(ProjectFieldTypeEnum.TIME.getIndex());
        entity.setCreateTime(DateUtil.getCommonDate());
        entity.setUpdateTime(DateUtil.getCommonDate());
        return projectFieldMapper.insert(entity);
    }

    /**
     * projectEntities转ProjectDOList
     *
     * @param projectEntities 项目实体列表
     * @return List<ProjectDO>
     * @author jy.zhao
     * @date 2021/9/28 16:29
     **/
    private List<ProjectDO> toProjectDOList(List<ProjectEntity> projectEntities) {
        List<ProjectDO> projectDOList = new ArrayList<>();
        if (Validator.isNull(projectEntities)) {
            return projectDOList;
        }
        for (ProjectEntity projectEntity : projectEntities) {
            projectDOList.add(toProjectDO(projectEntity));
        }
        return projectDOList;
    }

    /**
     * projectEntity转ProjectDO
     *
     * @param projectEntity 实体
     * @return ProjectDO do
     * @author jy.zhao
     * @date 2021/9/28 15:29
     **/
    private ProjectDO toProjectDO(ProjectEntity projectEntity) {
        if (Validator.isNull(projectEntity)) {
            return null;
        }
        ProjectDO projectDO = new ProjectDO();
        projectDO.setId(projectEntity.getProjectId());
        projectDO.setOrgId(projectEntity.getOrgId());
        projectDO.setName(projectEntity.getName());
        projectDO.setSurveyId(projectEntity.getSurveyId());
        projectDO.setTableId(projectEntity.getTableId());
        projectDO.setTableName(projectEntity.getTableName());
        // 设置时间字段
        List<ProjectFieldEntity> timeFieldEntities = projectFieldMapper.listProjectField(projectDO.getId(), ProjectFieldTypeEnum.TIME.getIndex());
        if (CollUtil.isNotEmpty(timeFieldEntities)) {
            ProjectFieldEntity projectFieldEntity = timeFieldEntities.get(0);
            projectDO.setTimeFieldId(projectFieldEntity.getFieldId());
            projectDO.setTimeFieldName(projectFieldEntity.getFieldName());
        }
        List<ProjectFieldEntity> textFieldEntities = projectFieldMapper.listProjectField(projectDO.getId(), ProjectFieldTypeEnum.TEXT.getIndex());
        // 设置文本字段
        List<ProjectFieldDO> textFieldList = new ArrayList<>();
        if (CollUtil.isNotEmpty(textFieldEntities)) {
            for (ProjectFieldEntity projectFieldEntity : textFieldEntities) {
                ProjectFieldDO projectFieldDO = new ProjectFieldDO();
                projectFieldDO.setId(projectFieldEntity.getFieldId());
                projectFieldDO.setValue(projectFieldEntity.getFieldName());
                projectFieldDO.setOffset(projectFieldEntity.getOffset());
                textFieldList.add(projectFieldDO);
            }
        }
        projectDO.setTextFieldList(textFieldList);
        projectDO.setTrainStatus(projectEntity.getTrainStatus());
        projectDO.setTrainProgress(projectEntity.getTrainProgress());
        projectDO.setStatus(projectEntity.getStatus());
        projectDO.setCreator(projectEntity.getCreatorId());
        projectDO.setCreatedId(projectEntity.getCreatorId());
        projectDO.setCreatedDate(projectEntity.getCreateTime());
        projectDO.setUpdatedId(projectEntity.getOperatorId());
        projectDO.setUpdatedDate(projectEntity.getUpdateTime());
        projectDO.setUpdatedDate(projectEntity.getUpdateTime());
        projectDO.setSample(projectEntity.getSample());
        projectDO.setModelId(projectEntity.getModelId());
        return projectDO;
    }

    /**
     * ProjectDO 转 projectEntity
     *
     * @param projectDO 实体
     * @return ProjectDO do
     * @author jy.zhao
     * @date 2021/9/28 15:29
     **/
    private ProjectEntity toProjectEntity(ProjectDO projectDO) {
        ProjectEntity projectEntity = new ProjectEntity();
        projectEntity.setProjectId(projectDO.getId());
        projectEntity.setOrgId(projectDO.getOrgId());
        projectEntity.setName(projectDO.getName());
        projectEntity.setSurveyId(projectDO.getSurveyId());
        projectEntity.setTableId(projectDO.getTableId());
        projectEntity.setTableName(projectDO.getTableName());
        projectEntity.setTrainStatus(projectDO.getTrainStatus());
        projectEntity.setTrainProgress(projectDO.getTrainProgress());
        projectEntity.setTrainProgress(projectDO.getTrainProgress());
        projectEntity.setModelId(projectDO.getModelId());
        projectEntity.setStatus(projectDO.getStatus());
        projectEntity.setCreatorId(projectDO.getCreatedId());
        projectEntity.setOperatorId(projectDO.getUpdatedId());
        return projectEntity;
    }


    /**
     * 封装结果
     *
     * @param projectDO          文本分析项目实体
     * @param projectFieldDOList 文本分析项目训练扩展字段List
     * @return ProjectDO
     */
    private ProjectDO toProjectDO(ProjectDO projectDO, List<ProjectFieldDO> projectFieldDOList) {
        projectDO.setTextFieldList(projectFieldDOList);
        return projectDO;
    }


    /**
     * entity to DO
     *
     * @param entity 文本分析项目训练扩展字段
     * @return ProjectFieldDO
     */
    private ProjectFieldDO toProjectFieldDO(ProjectFieldEntity entity) {
        ProjectFieldDO projectFieldDO = new ProjectFieldDO();
        projectFieldDO.setId(entity.getFieldId());
        projectFieldDO.setValue(entity.getFieldName());
        return projectFieldDO;
    }

}
